﻿using Nemerle.Collections;
using Nemerle.Text;
using Nemerle.Utility;
using Nemerle.Extensions;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Routing;
using System.Web.Mvc;
using System.Web.Hosting;
using System.Web.Mvc.Html;
using System.Web.Mvc.Ajax;


namespace System.Web.Mvc
{
    /* this code ported from T4MVC */

    public interface INRActionResult 
    {
        Action : string { get; set; }
        Controller : string { get; set; }
        RouteValueDictionary : RouteValueDictionary { get; set; }
    }
    
    public class NRActionResult : INRActionResult
    {
        public this(area : string, controller : string, action : string)  
        {
            Controller = controller;
            Action = action;
            RouteValueDictionary = RouteValueDictionary();
             
            RouteValueDictionary.Add("Controller", controller);
            RouteValueDictionary.Add("Action", action);
            RouteValueDictionary.Add("Area", area);
        }
         
        public Controller : string { get; set; }
        public Action : string { get; set; }
        public RouteValueDictionary : RouteValueDictionary { get; set; }
    }
    
    public module NRExtensions 
    {
        public ActionLink(this htmlHelper : HtmlHelper, linkText : string, result : INRActionResult) : MvcHtmlString 
        {
            htmlHelper.RouteLink(linkText, result.GetRouteValueDictionary());
        }

        public ActionLink(this htmlHelper : HtmlHelper, linkText : string, result : INRActionResult, htmlAttributes : object) : MvcHtmlString 
        {
            ActionLink(htmlHelper, linkText, result, RouteValueDictionary(htmlAttributes));
        }

        public ActionLink(this htmlHelper : HtmlHelper, linkText :  string, result : INRActionResult, htmlAttributes : IDictionary[string, object]) : MvcHtmlString
        {
            htmlHelper.RouteLink(linkText, result.GetRouteValueDictionary(), htmlAttributes);
        }

        public BeginForm(this htmlHelper : HtmlHelper, result : INRActionResult, formMethod :  FormMethod) : MvcForm 
        {
            htmlHelper.BeginForm(result, formMethod, null);
        }

        public BeginForm(this htmlHelper : HtmlHelper, result : INRActionResult, formMethod : FormMethod, htmlAttributes : object) : MvcForm
        {
            BeginForm(htmlHelper, result, formMethod, RouteValueDictionary(htmlAttributes));
        }

        public BeginForm(this htmlHelper : HtmlHelper, result : INRActionResult, formMethod : FormMethod, htmlAttributes : IDictionary[string, object]) : MvcForm
        {
            def callInfo = result;
            htmlHelper.BeginForm(callInfo.Action, callInfo.Controller, callInfo.RouteValueDictionary, formMethod, htmlAttributes);
        }

        public RenderAction(this htmlHelper : HtmlHelper, result : INRActionResult) : void {
            def callInfo = result;
            htmlHelper.RenderAction(callInfo.Action, callInfo.Controller, callInfo.RouteValueDictionary);
        }

        public Action(this htmlHelper : HtmlHelper, result : INRActionResult) : MvcHtmlString {
            htmlHelper.Action(result.Action, result.Controller, result.RouteValueDictionary);
        }
        public Action(this urlHelper : UrlHelper, result : INRActionResult) : string {
            urlHelper.RouteUrl(result.GetRouteValueDictionary());
        }

        public ActionAbsolute(this urlHelper : UrlHelper, result : INRActionResult) : string {
            string.Format("{0}{1}",urlHelper.RequestContext.HttpContext.Request.Url.GetLeftPart(UriPartial.Authority),
                urlHelper.RouteUrl(result.GetRouteValueDictionary()));
        }

        public ActionLink(this ajaxHelper : AjaxHelper, linkText : string, result : INRActionResult, ajaxOptions : AjaxOptions) : MvcHtmlString {
            ajaxHelper.RouteLink(linkText, result.GetRouteValueDictionary(), ajaxOptions);
        }

        public ActionLink(this ajaxHelper : AjaxHelper, linkText : string, result : INRActionResult, ajaxOptions : AjaxOptions, htmlAttributes : object) : MvcHtmlString {
            ajaxHelper.RouteLink(linkText, result.GetRouteValueDictionary(), ajaxOptions, RouteValueDictionary(htmlAttributes));
        }

        public ActionLink(this ajaxHelper : AjaxHelper, linkText : string, result : INRActionResult, ajaxOptions : AjaxOptions, htmlAttributes : IDictionary[string, object]) : MvcHtmlString {
            ajaxHelper.RouteLink(linkText, result.GetRouteValueDictionary(), ajaxOptions, htmlAttributes);
        }

        public MapRoute(this routes : RouteCollection, name : string, url : string, result : INRActionResult) : Route {
            routes.MapRoute(name, url, result, null : INRActionResult);
        }

        public MapRoute(this routes : RouteCollection, name : string, url : string, result : INRActionResult, defaults : object) : Route {
            MapRoute(routes, name, url, result, defaults, null);
        }

        public MapRoute(this routes : RouteCollection, name : string, url : string, result : INRActionResult, defaults : object, constraints : object) : Route {
            // Start by adding the default values from the anonymous object (if any)
            def routeValues = RouteValueDictionary(defaults);

            // Then add the Controller/Action names and the parameters from the call
            foreach (pair in result.GetRouteValueDictionary()) {
                routeValues.Add(pair.Key, pair.Value);
            }

            def routeConstraints = RouteValueDictionary(constraints);

            // Create and add the route
            def route = Route(url, routeValues, routeConstraints, MvcRouteHandler());
            routes.Add(name, route);
            route;
        }

        public GetRouteValueDictionary(this result : INRActionResult) : RouteValueDictionary {
            result.RouteValueDictionary;
        }

        public AddRouteValues(this result : INRActionResult, routeValues : object) : INRActionResult {
            result.AddRouteValues(RouteValueDictionary(routeValues));
        }

        public AddRouteValues(this result : INRActionResult, routeValues : RouteValueDictionary) : INRActionResult {
            def currentRouteValues = result.GetRouteValueDictionary();

            // Add all the extra values
            foreach (pair in routeValues) {
                currentRouteValues.Add(pair.Key, pair.Value);
            }

            result;
        }

        public AddRouteValues(this result : INRActionResult, nameValueCollection : System.Collections.Specialized.NameValueCollection) : INRActionResult {
            // Copy all the values from the NameValueCollection into the route dictionary
            nameValueCollection.CopyTo(result.GetRouteValueDictionary());
            result;
        }

        public AddRouteValue(this result : INRActionResult, name : string, value : object) : INRActionResult {
            def routeValues = result.GetRouteValueDictionary();
            routeValues.Add(name, value);
            result;
        }

        public AddRouteValue(this result : INRActionResult, coll : IAnonymous) : INRActionResult {
            def routeValues = result.GetRouteValueDictionary();
    
            foreach (field in coll.GetFields())
            {
                routeValues.Add(field, coll[field]);
            }
            result;
        }
    }
}
